module(..., package.seeall)

local brightness = nvm.get('brightness')

local function wake()
    if not pm.isleep('lcd') then return end
    pm.wake('lcd')
    disp.sleep(0)
    disp.update()
end

local function sleep()
    if pm.isleep('lcd') then return end
    disp.sleep(1)
    pm.sleep('lcd')
end

function setup()
    pm.wake('lcd')
    pmd.ldoset(0, pmd.KP_LEDR)
    pmd.ldoset(6, pmd.LDO_LCD)
    disp.init {
        width = 128,
        height = 128,
        bpp = 16,
        xoffset = 0,
        yoffset = 32,
        freq = 13000000,
        bus = disp.BUS_SPI4LINE,
        hwfillcolor = 65535,
        pinrst = pio.P0_14,
        pinrs = pio.P0_18,
        initcmd =
        {
            0xfe,
            0xef,
            0xb3,
            0x0030003,

            0xb6,
            0x030001,
            0xa3,
            0x030011,

            -- 0x35,
            -- 0x030000,
            -- 0x44,
            -- 0x030000, -- 调整scanline 可以调整切屏线至顶部或底部不可见区域

            0x21,
            0x36,
            0x00300c8,
            0x3a,
            0x0030005,
            0xb4,
            0x0030021,
            0xF0,
            0x003002d,
            0x0030054,
            0x0030024,
            0x0030061,
            0x00300ab,
            0x003002e,
            0x003002f,
            0x0030000,
            0x0030020,
            0x0030010,
            0x0030010,
            0x0030017,
            0x0030013,
            0x003000f,
            0xF1,
            0x0030002,
            0x0030022,
            0x0030025,
            0x0030035,
            0x00300a8,
            0x0030008,
            0x0030008,
            0x0030000,
            0x0030000,
            0x0030009,
            0x0030009,
            0x0030017,
            0x0030018,
            0x003000f,
            0xfe,
            0xff,
            0x11,
            0x010078,
            0x29,
        },
        sleepcmd = {
            0xfe,
            0xfe,
            0xef,
            0x28,
            0x010064,
            0x10,
            0x010064,
        },
        wakecmd = {
            0xfe,
            0xfe,
            0xef,
            0x11,
            0x010078,
            0x29,
            0x010064,
        }
    }
    disp.setbkcolor(BLACK)
    disp.clear()
    disp.update()
end

function setBrightness(val)
    brightness = val
    pmd.ldoset(val, pmd.KP_LEDR)
end

-- 背光工作模式定义
local BL_DISABLE = 0 -- 禁用
local BL_ALWAYS = 1 -- 常亮
local BL_SHORT = 2 -- 亮15秒后调整为低亮度，低亮度保持5秒后再关闭

-- 背光状态定义
local BL_OFF = 0
local BL_ON = 1
local BL_DIMMING = 2

local blmode = BL_SHORT
local blstate = BL_ON
local tags = {}
local offCallback

local function onTimeout()
    if blstate == BL_DIMMING then
        off()
    else
        blstate = BL_DIMMING
        pmd.ldoset(1, pmd.KP_LEDR) -- 背光第一次超时后先将亮度调低
        sys.timer_start(onTimeout, 5000)
    end
end

function onLcdOff(callback)
    offCallback = callback
end

--- lcd.turnon([tag]) 唤醒lcd，打开背光
-- @param [tag] 唤醒lcd的模块标记，带有标记时为常亮模式，必须对该标记turnoff才能重新恢复为延时灭屏
-- @return 无
-- @usage
-- lcd.turnon('call') -- call模块申请常亮lcd
-- lcd.turnon() -- 打开lcd并且一定时间后自动灭屏
function turnon(tag)
    if blmode == BL_DISABLE then return end
    local mode = tag and BL_ALWAYS or BL_SHORT
    if mode == BL_ALWAYS then tags[tag] = true end

    if blmode == BL_ALWAYS then return end -- 已经处于常亮模式

    if pm.isleep('lcd') then wake() end -- 打开屏幕

    pmd.ldoset(brightness, pmd.KP_LEDR) -- 打开背光

    -- 常亮则关闭定时器，否则启动定时器进行亮度调节
    if mode == BL_ALWAYS then
        sys.timer_stop(onTimeout)
    else
        sys.timer_start(onTimeout, 15000)
    end

    -- 更新状态
    blmode = mode
    blstate = BL_ON
end

--- lcd.turnoff(tag) 关闭lcd常亮模式
-- @param tag 关闭lcd常亮的模块标记
-- @return 无
-- @usage lcd.turnoff('call')
function turnoff(tag)
    if blmode == BL_DISABLE then return end
    if not tag then
        log.error('lcd.turnoff', 'no tag')
        return
    end
    tags[tag] = nil
    for _ in pairs(tags) do return end -- 若无申请lcd常亮的标签则切换进入背光SHORT模式
    blmode = BL_SHORT
    sys.timer_start(onTimeout, 15000)
end

--- lcd.off 立即关闭背光，休眠lcd
-- @param 无
-- @return 无
-- @usage lcd.off()
function off()
    pmd.ldoset(0, pmd.KP_LEDR)
    tags = {}
    sys.timer_stop(onTimeout)
    offCallback()
    sleep()
    blstate = BL_OFF
end

--- lcd.disable 禁用LCD
-- @param enter true-进入禁用模式 false-退出禁用模式
-- @return 无
-- @usage lcd.disable(true)
function disable(enter)
    if enter then
        off()
        blmode = BL_DISABLE
    else
        blmode = BL_SHORT
    end
end
